using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using MinimalistFoodStreet.BackEnd.Infrastructure.Attributes;
using MinimalistFoodStreet.BackEnd.Infrastructure.Dtos.Request.Functions;
using MinimalistFoodStreet.BackEnd.Infrastructure.Dtos.Request.Tables;
using MinimalistFoodStreet.BackEnd.Infrastructure.Dtos.Response;
using MinimalistFoodStreet.BackEnd.Infrastructure.Dtos.Response.Tables;
using MinimalistFoodStreet.BackEnd.Infrastructure.EFCore;
using MinimalistFoodStreet.BackEnd.Infrastructure.Tools;
using MinimalistFoodStreet.BackEnd.Server.IServer.Tables;
using MinimalistFoodStreet.BackEnd.Server.Server.RequestExtend.Tables;
using MinimalistFoodStreet.BackEnd.Server.Server.ResponseIqExtend;

namespace MinimalistFoodStreet.BackEnd.Server.Server.Tables
{
    [InjectClass]
    public class GoodsServer : IGoodsServer
    {
        private readonly ServerRepository _serverRepository;
        private readonly IConfiguration _configuration;

        public GoodsServer(DbContext dbContext, IConfiguration configuration)
        {
            _serverRepository = new ServerRepository(dbContext); _configuration = configuration;
        }

        public async Task<ResponseApiDto> AddAsync(RequestCreateGoodsDto dto)
        {
            if (!await _serverRepository.suppliersEFCore.Query(d => d.SShopName == dto.shopName).AnyAsync())
            {
                return ResponseApiDto.Fail($"没有该店铺\"{dto.shopName}\"");
            }
            if (dto.detailImages.Count > 20)
            {
                return ResponseApiDto.Fail("最多上传20张商品详情图片");
            }
            int affectedRows = 0;
            string imagePath = "";
            List<string> tempImagePaths = new List<string>();
            await _serverRepository.ExecuteInTransactionAsync(async () =>
            {
                // 添加商品
                Good good = dto.ToCreateEntity();
                good.GSupplierId = await _serverRepository.suppliersEFCore.Query(d => d.SShopName == dto.shopName).Select(d => d.SId).SingleAsync();
                good.GPhoto = "";
                good.GDetailImages = "";
                affectedRows += await _serverRepository.goodsEFCore.AddAsync(good);
                // 上传图片
                imagePath = Path.Combine(_configuration["ImageBasePath"], "Goods", good.GId.ToString());
                good.GPhoto = await Upload.UploadImageAsync(dto.photo, imagePath, true);
                tempImagePaths.Add(Path.Combine(imagePath, good.GPhoto));
                good.GDetailImages = "";
                for (int i = 0; i < dto.detailImages.Count; i++)
                {
                    if (good.GDetailImages != "") good.GDetailImages += ",";
                    string imageName = await Upload.UploadImageAsync(dto.detailImages[i], imagePath, true);
                    good.GDetailImages += imageName;
                    tempImagePaths.Add(Path.Combine(imagePath, imageName));
                }
                affectedRows += await _serverRepository.goodsEFCore.UpdateAsync(good);
            }, () =>
            {
                // 清理图片
                for (int i = 0; i < tempImagePaths.Count; i++)
                {
                    string tempImagePath = tempImagePaths[i];
                    if (File.Exists(tempImagePath))
                    {
                        File.Delete(tempImagePath);
                    }
                }
                // 删除文件夹
                if (Directory.Exists(imagePath))
                {
                    Directory.Delete(imagePath, true);
                }
                affectedRows = 0;
                return null;
            });
            return ResponseApiDto.Create(affectedRows);
        }

        public async Task<ResponseApiDto> UpdateAsync(RequestUpdateGoodsDto dto)
        {
            Good good = await _serverRepository.goodsEFCore.Query(d => d.GId == dto.id).SingleOrDefaultAsync();
            if (good == null)
            {
                return ResponseApiDto.Fail("该商品不存在");
            }
            if ((dto.retainDetailImages?.Count ?? 0) + (dto.detailImages?.Count ?? 0) > 20)
            {
                return ResponseApiDto.Fail("最多上传20张商品详情图片");
            }
            good.GName = dto.name;
            good.GPrice = dto.price;
            good.GDescription = dto.description;
            good.GSpecs = dto.specs;
            good.GIsDirectly = dto.isDirectly;
            good.GIsShelve = dto.isShelve;
            good.GInventory = dto.inventory;
            good.GBirthday = dto.birthday;
            good.GExpiryday = dto.expiryday;
            good.GIsPromote = dto.isPromote;
            good.GTopLevel = dto.topLevel;
            int affectedRows = 0;
            string imagePath = Path.Combine(_configuration["ImageBasePath"], "Goods", good.GId.ToString());
            List<FileInfo> tempDeletedImages = new List<FileInfo>();
            List<string> tempImagePaths = new List<string>();
            await _serverRepository.ExecuteInTransactionAsync(async () =>
            {
                // 删除图片
                if (dto.photo != null)
                {
                    if (File.Exists(Path.Combine(imagePath, good.GPhoto)))
                    {
                        tempDeletedImages.Add(new FileInfo(Path.Combine(imagePath, good.GPhoto)));
                        File.Delete(Path.Combine(imagePath, good.GPhoto));
                    }
                }
                List<string> detailImages = good.GDetailImages.Split(",").ToList();
                good.GDetailImages = "";
                for (int i = 0; i < detailImages.Count; i++)
                {
                    string detailImage = detailImages[i];
                    if (dto.retainDetailImages == null || !dto.retainDetailImages.Contains(detailImage))
                    {
                        if (File.Exists(Path.Combine(imagePath, detailImage)))
                        {
                            tempDeletedImages.Add(new FileInfo(Path.Combine(imagePath, detailImage)));
                            File.Delete(Path.Combine(imagePath, detailImage));
                        }
                    }
                    else
                    {
                        if (good.GDetailImages != "") good.GDetailImages += ",";
                        good.GDetailImages += detailImage;
                    }
                }
                // 新增图片
                if (dto.photo != null)
                {
                    string imageName = await Upload.UploadImageAsync(dto.photo, imagePath, true);
                    tempImagePaths.Add(Path.Combine(imagePath, imageName));
                    good.GPhoto = imageName;
                }
                if (dto.detailImages != null)
                {
                    for (int i = 0; i < dto.detailImages.Count; i++)
                    {
                        IFormFile detailImage = dto.detailImages[i];
                        string imageName = await Upload.UploadImageAsync(detailImage, imagePath, true);
                        tempImagePaths.Add(Path.Combine(imagePath, imageName));
                        if (good.GDetailImages != "") good.GDetailImages += ",";
                        good.GDetailImages += imageName;
                    }
                }
                affectedRows += await _serverRepository.goodsEFCore.UpdateAsync(good);
            }, () =>
            {
                // 删除图片
                foreach (var imagePath in tempImagePaths)
                {
                    if (File.Exists(imagePath))
                        File.Delete(imagePath);
                }
                // 恢复图片
                foreach (var deletedImage in tempDeletedImages)
                {
                    deletedImage.CopyTo(Path.Combine(imagePath, deletedImage.Name), overwrite: true);
                }
                affectedRows = 0;
                return null;
            });
            return ResponseApiDto.Create(affectedRows);
        }

        public async Task<ResponseApiDto> DeleteAsync(RequestDeleteGoodsDto dto)
        {
            if (!await _serverRepository.goodsEFCore.Query(d => d.GId == dto.id).AnyAsync())
            {
                return ResponseApiDto.Fail("不存在该商品");
            }
            int affectedRows = 0;
            Good good = await _serverRepository.goodsEFCore.Query(d => d.GId == dto.id).SingleAsync();
            string imagePath = Path.Combine(_configuration["ImageBasePath"], "Goods", good.GId.ToString());
            if (!Directory.Exists(imagePath))
            {
                Directory.CreateDirectory(imagePath);
            }
            List<FileInfo> tempDeletedImages = new List<FileInfo>();
            await _serverRepository.ExecuteInTransactionAsync(async () =>
            {
                // 删除商品
                affectedRows += await _serverRepository.goodsEFCore.Query(d => d.GId == dto.id).ExecuteDeleteAsync();
                // 删除图片
                List<string> detailImages = good.GDetailImages.Split(",").ToList();
                for (int i = 0; i < detailImages.Count; i++)
                {
                    string detailImage = detailImages[i];
                    if (File.Exists(Path.Combine(imagePath, detailImage)))
                    {
                        tempDeletedImages.Add(new FileInfo(Path.Combine(imagePath, detailImage)));
                        File.Delete(Path.Combine(imagePath, detailImage));
                    }
                }
                if (File.Exists(Path.Combine(imagePath, good.GPhoto)))
                {
                    tempDeletedImages.Add(new FileInfo(Path.Combine(imagePath, good.GPhoto)));
                    File.Delete(Path.Combine(imagePath, good.GPhoto));
                }
                //删除文件夹
                if (Directory.Exists(imagePath))
                {
                    Directory.Delete(imagePath);
                }
            }, () =>
            {
                // 恢复文件夹
                if (!Directory.Exists(imagePath))
                {
                    Directory.CreateDirectory(imagePath);
                }
                // 恢复图片
                foreach (var deletedImage in tempDeletedImages)
                {
                    deletedImage.CopyTo(Path.Combine(imagePath, deletedImage.Name), overwrite: true);
                }
                affectedRows = 0;
                return null;
            });
            return ResponseApiDto.Create(affectedRows);
        }

        public async Task<ResponseApiDto> DetailAsync(int id)
        {
            var iq = _serverRepository.goodsEFCore.Query(d => d.GId == id);
            if (!await iq.AnyAsync())
            {
                return ResponseApiDto.Fail("该实例不存在");
            }
            var resIq = iq.ToResponseGoodDetailIq();
            var data = await resIq.SingleAsync();
            data.createTimeStr = Tools.TimeToString(data.createTime);
            data.birthdayStr = Tools.TimeToString(data.birthday);
            data.updateTimeStr = Tools.TimeToString(data.updateTime);
            return ResponseApiDto.Ok("数据已获取", data);
        }

        public async Task<ResponseApiDto> PaginationAsync(int page, int limit, string? key, int? sid, int? gtid, int? isShelve)
        {
            int total = 0;
            var iq = _serverRepository.goodsEFCore.Query(d => (key == null || d.GName.Contains(key)) && (sid == null || d.GSupplierId == sid) && (gtid == null || d.GGoodTypeId == gtid) && (isShelve == null || d.GIsShelve == isShelve)).Include(g => g.Promotions.Where(p => p.PEndTime > DateTime.Now))
    .Include(g => g.GGoodType)
    .Include(g => g.GSupplier)
    .OrderByDescending(d => d.GTopLevel).ThenByDescending(d => d.GId);
            total = await iq.CountAsync();
            List<ResponseGoodsDto> goods = await iq.Skip((page - 1) * limit).Take(limit).ToResponseGoodDetailIq().ToListAsync();
            goods.ForEach((good) =>
            {
                good.createTimeStr = Tools.TimeToString(good.createTime);
                good.birthdayStr = Tools.TimeToString(good.birthday);
                good.updateTimeStr = Tools.TimeToString(good.updateTime);
            });
            return ResponseApiDto.Ok("数据已获取", new { data = goods, total });
        }

        public async Task<ResponseApiDto> SetIsShelve(SetIsShelveDto dto)
        {
            Good good = await _serverRepository.goodsEFCore.Query(d => d.GId == dto.id).SingleOrDefaultAsync();
            if (good == null)
            {
                return ResponseApiDto.Fail("该商品不存在");
            }
            good.GIsShelve = dto.isShelve == 0 ? 0 : 1;
            int affectedRows = await _serverRepository.goodsEFCore.UpdateAsync(good);
            return ResponseApiDto.Create(affectedRows);
        }

        public async Task<ResponseApiDto> GetGoodType()
        {
            int dtid = await _serverRepository.dictionaryTypesEFCore.Query(d => d.DtKey == "good_category").Select(d => d.DtId).SingleAsync();
            List<ResponseGoodTypeCountDto> gts = await _serverRepository.dictionarysEFCore.Query(d => d.DDictionaryTypeId == dtid && !d.InverseDParent.Any()).Select(d => new ResponseGoodTypeCountDto { gtid = d.DId, gtName = d.DValue }).ToListAsync();
            return ResponseApiDto.Ok("数据已获取", gts);
        }

        public async Task<ResponseApiDto> GetGoodTypeCount(int sid)
        {
            int dtid = await _serverRepository.dictionaryTypesEFCore.Query(d => d.DtKey == "good_category").Select(d => d.DtId).SingleAsync();
            List<ResponseGoodTypeCountDto> gts = await _serverRepository.dictionarysEFCore.Query(d => d.DDictionaryTypeId == dtid && !d.InverseDParent.Any() && d.Goods.Where(d => d.GSupplierId == sid).Count() > 0).Select(d => new ResponseGoodTypeCountDto { gtid = d.DId, gtName = d.DValue, gtCount = d.Goods.Count }).ToListAsync();
            return ResponseApiDto.Ok("数据已获取", gts);
        }

        public async Task<ResponseApiDto> SetTopLevel(SetTopLevelDto dto)
        {
            Good good = await _serverRepository.goodsEFCore.Query(d => d.GId == dto.id).SingleOrDefaultAsync();
            if (good == null)
            {
                return ResponseApiDto.Fail("该商品不存在");
            }
            good.GTopLevel = dto.topLevel;
            int affectedRows = await _serverRepository.goodsEFCore.UpdateAsync(good);
            return ResponseApiDto.Create(affectedRows);
        }

        public async Task<ResponseApiDto> Replenishment(ReplenishmentDto dto)
        {
            Good good = await _serverRepository.goodsEFCore.Query(d => d.GId == dto.id).SingleOrDefaultAsync();
            if (good == null)
            {
                return ResponseApiDto.Fail("该商品不存在");
            }
            good.GInventory += dto.count;
            int affectedRows = await _serverRepository.goodsEFCore.UpdateAsync(good);
            return ResponseApiDto.Create(affectedRows);
        }

        public async Task<ResponseApiDto> GetGoodHot(int page, int limit)
        {
            int total = 0;
            var iq = _serverRepository.goodsEFCore.Query(d => d.GIsShelve == 1)
                .OrderByDescending(d => d.OrderDetails.Where(d => d.OdOrder.OCompleteTime != null).Sum(d => d.OdCount) * 1 + d.OrderDetails.Where(d => d.OdOrder.OCompleteTime != null && d.OdOrder.OCompleteTime >= DateTime.Now.AddDays(-30)).Sum(d => d.OdCount) * 3 + d.OrderDetails.Where(d => d.OdOrder.OCompleteTime != null && d.OdOrder.OCompleteTime >= DateTime.Now.AddDays(-7)).Sum(d => d.OdCount) * 7)
                .ThenByDescending(d => d.GId);
            total = await iq.CountAsync();
            List<ResponseGoodList> goods = await iq.Skip((page - 1) * limit).Take(limit).Select(entity => new ResponseGoodList
            {
                id = entity.GId,
                name = entity.GName,
                spec = entity.GSpecs,
                price = entity.GPrice,
                photo = entity.GPhoto,
                promotePrice = entity.Promotions != null && entity.Promotions.Where(d => d.PEndTime > DateTime.Now).FirstOrDefault() != null ?
                       entity.Promotions.Where(d => d.PEndTime > DateTime.Now).FirstOrDefault().PDiscountPrice : 0,
                saleCout = entity.OrderDetails.Where(d => d.OdOrder.OCompleteTime != null).Sum(d => d.OdCount)
            }).ToListAsync();
            return ResponseApiDto.Ok("数据已获取", new { data = goods, total });
        }

        public async Task<ResponseApiDto> GetGoodPromote(int page, int limit)
        {
            int total = 0;
            var iq = _serverRepository.goodsEFCore.Pagination(d => d.GIsShelve == 1 && d.Promotions.Where(d => d.PEndTime > DateTime.Now).Any(), false, d => d.GId, out total, page, limit);
            List<ResponseGoodList> goods = await iq.Select(entity => new ResponseGoodList
            {
                id = entity.GId,
                name = entity.GName,
                spec = entity.GSpecs,
                price = entity.GPrice,
                photo = entity.GPhoto,
                promotePrice = entity.Promotions != null && entity.Promotions.Where(d => d.PEndTime > DateTime.Now).FirstOrDefault() != null ?
                       entity.Promotions.Where(d => d.PEndTime > DateTime.Now).FirstOrDefault().PDiscountPrice : 0,
                saleCout = entity.OrderDetails.Where(d => d.OdOrder.OCompleteTime != null).Sum(d => d.OdCount)
            }).ToListAsync();
            return ResponseApiDto.Ok("数据已获取", new { data = goods, total });
        }

        public async Task<ResponseApiDto> GetGoodPagnation(int page, int limit, int? gtid, string? key)
        {
            int total = 0;
            var iq = _serverRepository.goodsEFCore.Pagination(d => d.GIsShelve == 1 && (gtid == null || d.GGoodTypeId == gtid) && (key == null || d.GName.Contains(key)), false, d => d.GId, out total, page, limit);
            List<ResponseGoodList> goods = await iq.Select(entity => new ResponseGoodList
            {
                id = entity.GId,
                name = entity.GName,
                spec = entity.GSpecs,
                price = entity.GPrice,
                photo = entity.GPhoto,
                promotePrice = entity.Promotions != null && entity.Promotions.Where(d => d.PEndTime > DateTime.Now).FirstOrDefault() != null ?
                       entity.Promotions.Where(d => d.PEndTime > DateTime.Now).FirstOrDefault().PDiscountPrice : 0,
                saleCout = entity.OrderDetails.Where(d => d.OdOrder.OCompleteTime != null).Sum(d => d.OdCount)
            }).ToListAsync();
            return ResponseApiDto.Ok("数据已获取", new { data = goods, total });
        }

        public async Task<ResponseApiDto> GetGoodDetail(int id, int bid)
        {
            var iq = _serverRepository.goodsEFCore.Query(d => d.GId == id);
            if (!await iq.AnyAsync())
            {
                return ResponseApiDto.Fail("没有该商品");
            }

            var data = await iq.Select(entity => new ResponseGoodDetail
            {
                id = entity.GId,
                rate = entity.Comments != null && entity.Comments.Count > 0 ? entity.Comments.Average(d => d.CRate ?? 0) : 0,
                inventory = entity.GInventory,
                sid = entity.GSupplierId,
                name = entity.GName,
                spec = entity.GSpecs,
                price = entity.GPrice,
                detailImages = entity.GDetailImages,
                promotePrice = entity.Promotions != null ? entity.Promotions.Where(d => d.PEndTime > DateTime.Now).First().PDiscountPrice : null,
                saleCout = entity.OrderDetails
                    .Where(d => d.OdOrder.OCompleteTime != null)
                    .Sum(d => d.OdCount),
                isCollected = entity.Collections.Any() ? 1 : 0,
                cid = entity.Collections != null && entity.Collections.Where(d => d.CBusinessId == bid && d.CGoodId == id).Any() ? entity.Collections.Where(d => d.CBusinessId == bid && d.CGoodId == id).First().CId : null
            }).SingleOrDefaultAsync();

            if (data != null)
            {
                data.cartCount = await _serverRepository.chartsEFCore
                    .Query(d => d.CBusinessId == bid)
                    .CountAsync();
            }

            return ResponseApiDto.Ok("数据已获取", data);
        }
    }
}